{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial: Peralatan Dasar untuk Privasi Pembelajaran Dalam (*Private Deep Learning*)\n",
    "\n",
    "Selamat datang di tutorial pengantar PySft untuk menjaga privasi, pembelajaran dalam terdesentralisasi. Rangkaian buku catatan ini (Jupyter notebooks) adalah panduan tahap demi tahap agar anda dapat mengetahui peralatan dan teknik baru yang diperlukan untuk menjalankan pembelajaran dalam pada model/data privat/rahasia tanpa tersentralisasi dalam otoritas tunggal.\n",
    "\n",
    "**Cakupan:** Perhatikan bahwa kita tidak akan hanya membahas tentang bagaimana mendesentralisasi atau mengenkripsi data, tapi kita juga akan menekankan bagaimana PySyft akan digunakan untuk membantu desentralisasi dari keseluruhan ekosistem seputar data, bahkan termasuk basis data (*database*) dimana data disimpan dan dikueri, dan model saraf tiruan (*neural models*) yang digunakan untuk mengekstrak informasi dari data. Dengan ekstensi-ekstensi PySyft yang baru telah dibuat, buku catatan ini akan ditambahkan dengan tutorial-tutorial baru untuk menjelaskan fungsionalitas yang baru.\n",
    "\n",
    "Pengarang:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "\n",
    "Penerjemah:\n",
    "- Linggih Saputro - Twitter: [@__nggih](https://twitter.com/__nggih)\n",
    "\n",
    "## Ikhtisar:\n",
    "\n",
    "- Bagian 1: Peralatan Dasar untuk Privasi Pembelajaran Dalam\n",
    "\n",
    "## Mengapa Perlu Mengambil Tutorial Ini?\n",
    "\n",
    "**1) Karir dengan Keunggulan Kompetitif** - Dalam 20 tahun belakangan ini, revolusi digital telah mempermudah data untuk dapat diakses dalam kuantitas yang besar seiring dengan proses-proses analog yang telah didigitalisasi. Akan tetapi, dengan peraturan baru seperti [GDPR](https://eugdpr.org/), perusahaan-perusahan ditekan agar tidak leluasa menggunakan data mereka - dan yang lebih penting lagi, bagaimana mereka menganalisis informasi personal. **Garis Bawah:** Ilmuwan data tidak akan memiliki akses terhadap data dengan peralatan \"kuno\", tapi dengan mempelajari peralatan Privasi Pembelajaran Dalam, ANDA bisa lebih maju dan memperoleh keunggulan kompetitif di karir anda.\n",
    "\n",
    "**2) Peluang Bisnis** - Terdapat begitu banyak permasalahan di masyarakat yang dapat diselesaikan dengan Pembelajaran Dalam, tapi banyak dari permasalahan yang paling penting belum dapat dieksplorasi karena dibutuhkan akses terhadap informasi yang sangat sensitif milik banyak orang (pertimbangkan penggunaan Pembelajaran Dalam untuk membantu orang dengan masalah mental atau hubungan!). Maka dari itu, belajar Privasi Pembelajaran Dalam membuka begitu banyak peluang perusahaan rintisan (*start-up*) baru untuk anda yang sebelumnya tidak tersedia tanpa peralatan ini.\n",
    "\n",
    "**3) Kebaikan Sosial** - Pembelajaran Dalam dapat digunakan untuk menyelesaikan bermacam-macam masalah di dunia nyata, tapi Pembelajaran Dalam akan *informasi personal* adalah Pembelajaran Dalam tentang orang-orang, *untuk orang-orang*. Belajar bagaimana melakukan Pembelajaran Dalam pada data yang tidak anda miliki, menunjukkan lebih dari sekedar peluang karir atau bisnis, ini adalah peluang untuk membantu menyelesaikan beberapa dari masalah-masalah personal dan penting dalam hidup orang-orang - dan melakukannya dalam skala besar.\n",
    "\n",
    "\n",
    "## Bagaimana saya dapat memperoleh kredit ekstra?\n",
    "- Bintangi PySyft di GitHub! -[https://github.com/OpenMined/PySyft](https://github.com/OpenMined/PySyft)\n",
    "- Mengajarkan buku catatan (*jupyter notebook) ini lewat video Youtube!\n",
    "\n",
    "... oke ... mari kita mulai!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part -1: Prasyarat\n",
    "- Mengenal PyTorch - jika tidak, maka pelajari kuliah http://fast.ai dahulu kemudian kembali lagi kemari.\n",
    "- Bacalah jurnal PySyft Framework https://arxiv.org/pdf/1811.04017.pdf! Ini akan memberikan anda latar belakang yang menyeluruh tentang bagaimana PySyft dibentuk, yang akan menjadikan hal-hal ini lebih masuk akal."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 0: Setup\n",
    "\n",
    "Untuk memulai, anda harus memastikan instalasi anda benarr. Bacalah PySyft bagian README di laman PySyft dan ikuti instruksi instalasi.\n",
    "\n",
    "- Pasang Python 3.6 atau versi lebih tinggi\n",
    "- Pasang PyTorch 1.3\n",
    "- Klon (*clone*) PySyft (git clone https://github.com/OpenMined/PySyft.git)\n",
    "- cd PySyft\n",
    "- pip install -r pip-dep/requirements.txt\n",
    "- pip install -r pip-dep/requirements_udacity.txt\n",
    "- python setup.py install udacity\n",
    "- python setup.py test\n",
    "\n",
    "Jika ada bagian yang tidak jalan (atau tes apapun yang gagal) - periksa terlebih dahulu [README](https://github.com/OpenMined/PySyft.git) untuk bantuan instalasi lalu buka GitHub Issue atau kabari kanal #beginner di Slack kami! [slack.openmined.org](http://slack.openmined.org/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING:root:Torch was already hooked... skipping hooking process\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([1, 2, 3, 4, 5])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Jalankan sel ini untuk memastikan semuanya berjalan dengan baik (Shift+Enter)\n",
    "import sys\n",
    "\n",
    "import torch\n",
    "from torch.nn import Parameter\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(torch)\n",
    "\n",
    "torch.tensor([1,2,3,4,5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Jika sel di atas dijalankan, maka anda dapat memulai yang selanjutnya! Mari kita lanjutkan!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bagian 1: Peralatan untuk Ilmu Data yang Terdesentralisasi dan Privat\n",
    "\n",
    "Jadi - pertanyaan pertama anda mungkin - Bagaimana kita dapat melatih model di data tanpa kita dapat akses?\n",
    "\n",
    "Jawabannya mungkin sangat sederhana. Jika anda terbiasa bekerja dengan PyTorch, maka anda juga terbiasa bekerja dengan objek-objek torch.Tensor seperti ini!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([ 2,  4,  6,  8, 10])\n"
     ]
    }
   ],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = x + x\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Jelas, sangat penting menggunakan tensor yang super lucu dan kuat ini, tapi juga mengharuskan anda memiliki data di mesin lokal anda. Dari sinilah perjalanan anda dimulai.\n",
    "\n",
    "# Bab 1.1 - Mengirimkan Tensor ke Mesinnya Bob\n",
    "\n",
    "Sedangkan biasanya kita melakukan ilmu data/ Pembelajaran Dalam di mesin yang terdapat data tersebut, sekarang, kita ingin melakukan komputasi di mesin **lain**. Terlebih secara khusus, kita tidak dapat berasumsi data tersebut terdapat di mesin lokal kita.\n",
    "\n",
    "Dengan demikian, alih-alih menggunakan tensor Torch, kita akan bekerja dengan **pointer** ke tensor. Izinkan saya tunjukkan yang saya maksud. Pertama, marilah kita buat mesin \"bohongan\" yang dimiliki oleh orang \"bohongan\" - sebut saja namanya Bob."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Katakanlah mesinnya Bob ada di planet lain - mungkin saja di Mars! Tapi, sekarang ini mesinnya kosong. Mari kita buat beberapa data agar kita dapat mengirimnya ke Bob dan belajar tentang *pointer*!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5])\n",
    "y = torch.tensor([1,1,1,1,1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dan sekarang - marilah kita kirim tensor kita ke Bob!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_ptr = x.send(bob)\n",
    "y_ptr = y.send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:43091033991 -> bob:80505619433]"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "DOR! Sekarang si Bob punya dua tensor! Ga percaya? Kita buktikan bersama!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{80505619433: tensor([1, 2, 3, 4, 5]), 16737735861: tensor([1, 1, 1, 1, 1])}"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x_ptr + x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:30357512505 -> bob:36076025945]"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{80505619433: tensor([1, 2, 3, 4, 5]),\n",
       " 16737735861: tensor([1, 1, 1, 1, 1]),\n",
       " 36076025945: tensor([ 2,  4,  6,  8, 10])}"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sekarang dapat kita perhatikan. Ketika kita panggil `x.send(bob)`, itu mengembalikan objek baru yang kita sebut dengan `x_ptr`. Ini adalah *pointer* pertama kita untuk sebuah tensor. *Pointer* ke tensor TIDAK menyimpan data itu sendiri. Melainkan, mereka menyimpan metadata tentang tensor (dengan data) disimpan di mesin lainnnya. Tujuan dari tensor-tensor ini adalah untuk menyediakan API yang intuitif untuk memberitahukan mesin yang lainnya untuk menghitung fungsi-fungsi menggunakan tensor ini. Mari kita lihat metadata yang disimpan *pointer-pointer* tersebut.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:43091033991 -> bob:80505619433]"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Mari kita periksa metadata tersebut!\n",
    "\n",
    "Terdapat dua atribut utama yang spesifik terhadap *pointer-pointer* tersebut:\n",
    "\n",
    "- `x_ptr.location : bob`, sebuah referensi ke lokasi yang ditunjuk oleh *pointer* \n",
    "- `x_ptr.id_at_location : <random integer>`, dengan tipe data bilangan bulat yang acak, menyediakan identitas (id) lokasi tensor itu disimpan.\n",
    "\n",
    "Mereka dicetak dengan format `<id_at_location>@<location>`\n",
    "\n",
    "Terdapat juga atribut umum lainnya:\n",
    "- `x_ptr.id : <random integer>`, dengan tipe data bilangan, identitas (id) dari tensor *pointer* kita, yang dialokasikan secara acak.\n",
    "\n",
    "- `x_ptr.owner : \"me\"`, pekerja (*worker*) yang memiliki tensor *pointer*, dalam contoh ini, pekerja (*worker*) lokal, yang dinamakan \"me\"\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<VirtualWorker id:bob #objects:3>"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<VirtualWorker id:bob #objects:3>"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bob"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bob == x_ptr.location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "80505619433"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr.id_at_location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<VirtualWorker id:me #objects:0>"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Anda penasaran 'kan kenapa pekerja (*worker*) lokal yang memiliki *pointer* juga adalah sebuah VirtualWorker, walaupun kita tidak membuatnya.\n",
    "Fakta lucu nih, sama seperti objek VirtualWorker untuk Bob, kita juga punya satu untuk kita (secara standar). Pekerja (*worker*) ini secara otomatis dibuat ketika kita memanggil `hook = sy.TorchHook()`, sehingga kita tidak perlu membuatnya sendiri. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<VirtualWorker id:me #objects:0>"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "me = sy.local_worker\n",
    "me"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "me == x_ptr.owner"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dan akhirnya, sama seperti kita dapat memanggil .send() di sebuah tensor, we juga dapat memanggil .get() di sebuah *pointer* untuk sebuah tensor untuk memperoleh tensor itu kembali!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:43091033991 -> bob:80505619433]"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1, 2, 3, 4, 5])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:71376756070 -> bob:16737735861]"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1, 1, 1, 1, 1])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_ptr.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([ 2,  4,  6,  8, 10])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bob._objects"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dan seperti yang anda lihat... Bob tidak punya tensor apapun lagi!! Mereka kembali ke mesin kita!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Bab 1.2 - Menggunakan *Pointer* Tensor\n",
    "\n",
    "Mengirim dan menerima tensor dari Bob memang keren, tapi ini bukanlah Pembelajaran Dalam! Kami ingin anda dapat melakukan _operations_ tensor di tensor yang jauh. Untungnya, *pointer* tensor mempermudah hal ini! Anda dapat menggunakan *pointer* seperti tensor normal anda!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5]).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1]).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = x + y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:94856264424 -> bob:28561975221]"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Voilà! \n",
    "\n",
    "Di belakang layar, sesuatu yang sangat kuat terjadi. Alih-alih menghitung penjumlahan x dan y di lokal, perintah diserialisasi dan dikirim ke Bob, yang melakukan komputasi, membuat sebuah tensor z, dan lalu mengembalikan pointer z ke kita!\n",
    "\n",
    "Jika kita memanggil .get() di *pointer*, kita akan menerima hasilnya di mesin kita!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([2, 3, 4, 5, 6])"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Fungsi-Fungsi Torch\n",
    "\n",
    "API ini dikembangkan untuk semua operasi Torch!!!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:74208622935 -> bob:43188411715]"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:35512884634 -> bob:65201623471]"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:64176255024 -> bob:89886033678]"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z = torch.add(x,y)\n",
    "z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([2, 3, 4, 5, 6])"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Variabel (termasuk *backpropagation!)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = torch.tensor([1,2,3,4,5.], requires_grad=True).send(bob)\n",
    "y = torch.tensor([1,1,1,1,1.], requires_grad=True).send(bob)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "z = (x + y).sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(Wrapper)>[PointerTensor | me:27916487465 -> bob:61790140014]"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "z.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = x.get()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1., 2., 3., 4., 5.], requires_grad=True)"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1., 1., 1., 1., 1.])"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Seperti yang anda dapat saksikan, API ini sangat fleksibel dan mampu melakukan operasi apapun yang anda ingin lakukan di Torch pada *remote data*. Inilah dasar dari protokol penjagaan privasi tingkat lanjut seperti    *Federated Learning, Secure Multi-Party Computation, dan Differential Privacy* !"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Congratulations!!! - Time to Join the Community!\n",
    "\n",
    "Congratulations on completing this notebook tutorial! If you enjoyed this and would like to join the movement toward privacy preserving, decentralized ownership of AI and the AI supply chain (data), you can do so in the following ways!\n",
    "\n",
    "# Selamat!!! - Saatnya Bergabung ke Komunitas\n",
    "\n",
    "Selamat karena telah menyelesaikan tutorial ini! Jika anda menikmatinya dan ingin bergabung dengan gerakan menuju pertahanan privasi, kepemilikan terdesentralisasi dari AI dan rantai suplai AI (data), anda dapat melakukannya dengan berbagai cara berikut!\n",
    "\n",
    "### Bintangi PySyft di GitHub\n",
    "\n",
    "Cara termudah untuk membantu komunitas ini adalah hanya dengan memberikan bintang di repo GitHub! Hal ini membantu meningkatkan kesadaran akan peralatan keren yang lagi dibuat.\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Bergabung dengan Slack kami!\n",
    "\n",
    "Cara terbaik untuk tetap terkini akan kemajuan termutakhir adalah dengan bergabung ke komunitas kami! Anda dapat mengisi form berikut\n",
    "[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### Bergabung dengan Project Kode!\n",
    "\n",
    "Cara terbaik untuk berkontribusi ke komunitas ini adalah dengan menjadi kontributor kode! Kapanpun anda dapat pergi ke laman PySyft GitHub Issues dan filter \"Projects\". Ini akan memperlihatkan anda gambaran umum Tickets terhadap suatu proyek yang akan anda ikut serta! Jika anda tidak ingin bergabung suatu proyek, tapi ini mengoding sedikit, anda dapat juga mencari mini-proyek dengan mencari di GitHub issues tanda \"good first issue\".\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### Donasi\n",
    "\n",
    "Jika anda tidak memiliki waktu untuk berkontribusi ke basis kode kami, tapi tetap ingin memberikan dukungan, anda dapat juga menjadi Backer di Open Collective kami. Semua donasi akan ditujukan ke hosting web dan pengeluaran komunitas yang lain seperti hackathon dan meetup!\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
